package yxy.game.pm2.proto;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

import com.alibaba.fastjson.JSONArray;

import yxy.apple.util.FileUtility;
import yxy.apple.util.JSONUtility;

public class ProtobufCompiler {
	private static final String MacCOMPILER_PATH = "game.pm2.proto/protoc/3.12.2/protoc.osx";
	private static final String WinCOMPILER_PATH = "game.pm2.proto/protoc/3.12.2/protoc.win64.exe";

	public static final String SRC_PROTO_DIR = "game.pm2.proto/proto";

	private static final String OUTPUT_JAVA_DIR = "game.pm2.proto/src/main/java/";

	public static void main(String[] args) {
		try {
			{
//				String commandDIR = OUTPUT_JAVA_DIR + "yxy/game/pm2/command";
//				FileUtility.remove(new File(commandDIR));
//				FileUtility.make(new File(commandDIR));

//				String messageDIR = OUTPUT_JAVA_DIR + "yxy/game/pm2/message";
//				FileUtility.remove(new File(messageDIR));
			}
			// *
			//JSONArray commands = JSONUtility.readArray(new File(SRC_PROTO_DIR + "/Command.json"));
			JSONArray message = JSONUtility.readArray(new File(SRC_PROTO_DIR + "/game.json"));
			{
				System.out.println("Compling Java files...");
				File root = new File(SRC_PROTO_DIR);
				compile(root, true, "java", OUTPUT_JAVA_DIR);

				System.out.println("Generating Java constants file...");
				CommandGeneratorJava generator = new CommandGeneratorJava(true, "yxy.game.pm2.command", "Command");
				generator.generate(message, OUTPUT_JAVA_DIR, "UTF-8");

				CommandGeneratorProto generator2 = new CommandGeneratorProto(true, "yxy.game.pm2.command", "CommandMessage");
				generator2.generate(message, OUTPUT_JAVA_DIR, "UTF-8");

				CommandGeneratorJs generatorJs = new CommandGeneratorJs(true, "yxy.game.pm2.command", "Command");
				generatorJs.generate(message, OUTPUT_JAVA_DIR, "UTF-8");
			}
			// */

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static void compile(File root, boolean recursive, String language, String output) throws Exception {
		if (root.exists() && root.isDirectory()) {
			String[] items = root.list();
			for (String item : items) {
				File file = new File(root.getAbsolutePath() + "/" + item);
				if (file.isFile()) {
					if (file.getName().endsWith(".proto")) {
						if (!ProtobufCompiler.compile(file, language, output)) {
							throw new Exception();
						}
					}
				} else if (file.isDirectory() && recursive) {
					ProtobufCompiler.compile(file, true, language, output);
				}
			}
		} else {
			if (!ProtobufCompiler.compile(root, language, output)) {
				throw new Exception();
			}
		}
	}

	private static boolean compile(File file, String language, String output) throws Exception {
		System.out.printf("Compiling %s...", file.getCanonicalPath());
		StringBuffer buffer = new StringBuffer();
		String os = System.getProperty("os.name");
		if (os.toLowerCase().startsWith("mac")) {
			buffer.append(MacCOMPILER_PATH);
		} else {
			buffer.append(WinCOMPILER_PATH);
		}
		buffer.append(" ");
		buffer.append("-I=");
		buffer.append(new File(SRC_PROTO_DIR).getAbsolutePath());
		buffer.append(" ");
		buffer.append("--");
		buffer.append(language);
		buffer.append("_out=");
		buffer.append(output);
		buffer.append(" ");
		buffer.append(file.getAbsolutePath());

		String command = buffer.toString();
//		 System.out.println(command);
		Process process = Runtime.getRuntime().exec(command);
//		System.out.println(process.isAlive());
		process.waitFor();
//		System.out.println("111111111");
		if (process.exitValue() == 0) {
			System.out.println("Done!");
			return true;
		} else {
			System.err.println("Failed!");
			String result = ProtobufCompiler.read(process.getErrorStream(), 32768);
			System.err.println(result);
			return false;
		}
	}

	private static String read(InputStream is, int length) throws IOException {
		ByteBuffer buffer = ByteBuffer.allocate(length);
		byte[] bytes = new byte[8192];
		int got = is.read(bytes);
		int saved = 0;
		while (got != -1) {
			buffer.put(bytes, 0, got);
			saved += got;
			if (saved >= length) {
				break;
			} else {
				got = is.read(bytes);
			}
		}
		return new String(buffer.array());
	}
}
